﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GMUtilitiesDotNet.Threading;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ThouShaltNotBrickLevelEditor.Code.Helpers;
using System.Windows;
using ThouShaltNotBrickLevelEditor.Code.GeneralObjects;
using ThouShaltNotBrick.Models;
using ThouShaltNotBrickLevelEditor.Models;

namespace ThouShaltNotBrickLevelEditor.Code.Renderers
{
    internal sealed class LevelRenderer : IWorker<LevelRendererParameters, LevelRendererReturnValue>
    {
        #region Overriden Methods
        public LevelRendererReturnValue Work(LevelRendererParameters pParameters)
        {
            if (pParameters == null ||
                pParameters.BrickStatesTypesImages == null ||
                pParameters.LevelData == null)
            {
                return null;
            }

            if (pParameters.ControlWidth < 1.0 || pParameters.ControlHeight < 1.0)
            {
                return null;
            }

            DrawingVisual dv = new DrawingVisual();
            using (DrawingContext dc = dv.RenderOpen())
            {
                Draw(
                    dc,
                    pParameters);
            }

            RenderTargetBitmap levelBitmap = RendererHelpers.CreateRenderTargetBitmap(
                (int)pParameters.ControlWidth,
                (int)pParameters.ControlHeight);

            levelBitmap.Render(dv);
            levelBitmap.Freeze();

            return new LevelRendererReturnValue(
                levelBitmap);
        }
        #endregion

        #region Methods
        private static void Draw(
            DrawingContext pDc,
            LevelRendererParameters pParameters)
        {
            DrawLevelGrid(pDc);
            DrawBricks(pDc, pParameters);
        }

        private static void DrawLevelGrid(
            DrawingContext pDc)
        {
            Pen gridPen = new Pen(Brushes.Black, 2.0);
            DrawHorizonalLevelGridLines(pDc, gridPen);
            DrawVerticalLevelGridLines(pDc, gridPen);
        }

        private static void DrawHorizonalLevelGridLines(
            DrawingContext pDc,
            Pen pPen)
        {
            double x0 = 0.0;
            double x1 = Constants.LEVEL_WIDTH;
            double y;
            for (int i = 0; i <= Constants.BRICK_ROWS; i++)
            {
                y = i * Constants.BRICK_HEIGHT;
                Point pt0 = new Point(x0, y);
                Point pt1 = new Point(x1, y);
                pDc.DrawLine(pPen, pt0, pt1);
            }
        }

        private static void DrawVerticalLevelGridLines(
            DrawingContext pDc,
            Pen pPen)
        {
            double x;
            double y0 = Constants.LEVEL_HEIGHT;
            double y1 = 0.0;
            for (int i = 0; i <= Constants.BRICK_COLUMNS; i++)
            {
                x = i * Constants.BRICK_WIDTH;
                Point pt0 = new Point(x, y0);
                Point pt1 = new Point(x, y1);
                pDc.DrawLine(pPen, pt0, pt1);
            }
        }

        private static void DrawBricks(
            DrawingContext pDc,
            LevelRendererParameters pParameters)
        {
            BrickStatesTypesImages brickStatesTypesImages = pParameters.BrickStatesTypesImages;
            BrickTypesData brickTypesData = brickStatesTypesImages.BrickTypesData;
            BrickStatesData brickStatesData = brickStatesTypesImages.BrickStatesData;
            BrickStateImages brickStateImages = brickStatesTypesImages.BrickStateImages;

            LevelData levelData = pParameters.LevelData;
            List<BrickData> brickList = levelData.GetBricks();
            foreach (BrickData brick in brickList)
            {
                BrickTypeData brickType = brickTypesData.GetBrickType(brick.TypeName);
                string brickStateName = brickType.GetBrickStates()[brick.InitialBrickStateIndex];
                BitmapImage brickStateImage = brickStateImages.GetBrickStateImage(brickStateName);
                Rect brickRect = GetBrickRect(brick.Row, brick.Column);
                pDc.DrawImage(brickStateImage, brickRect);
            }
        }

        private static Rect GetBrickRect(
            int pRow,
            int pColumn)
        {
            double x = pColumn * Constants.BRICK_WIDTH;
            double y = Constants.LEVEL_HEIGHT - Constants.BRICK_HEIGHT - pRow * Constants.BRICK_HEIGHT;
            return new Rect(
                x,
                y,
                Constants.BRICK_WIDTH,
                Constants.BRICK_HEIGHT);
        }
        #endregion
    }
}